﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using DirectCanvas;
using DirectCanvas.Brushes;
using DirectCanvas.Imaging;
using DirectCanvas.Misc;
using DirectCanvas.Shapes;
using DirectCanvas.Transforms;
using DirectCanvas.Scenes;

namespace WindowsFormsTest.Demos.GeometryDemo
{
    class GeometryScene : Scene
    {
        private readonly Presenter m_presenter;
        private PathGeometry m_pathGeometry;
        private SolidColorBrush m_solidColorBrush;
        private bool m_mousedown;
        private PointF m_mousePosition;

        private const int SCENE_WIDTH = 1200;
        private const int SCENE_HEIGHT = 1000;
        
        private LinearGradientBrush m_gradientBrush;
        private DrawingLayer m_bitmap;
        private DrawingLayerBrush m_bitmapBrush;
        private RadialGradientBrush m_radialBrush;
        private RotateTransform m_rotateTransform = new RotateTransform();

        public GeometryScene(Presenter presenter)
        {
            m_presenter = presenter;
            Initialize();
        }

        public override void SetInputState(int inputId, InputStatus status, PointF position)
        {
            m_mousedown = status == InputStatus.Down;
            m_mousePosition = position;
        }

        public override void Render()
        {
            m_rotateTransform.Angle++;

            m_radialBrush.Alignment = BrushAlignment.GeometryRelative;
            m_gradientBrush.Alignment = BrushAlignment.GeometryRelative;

            m_presenter.Clear();
            m_presenter.BeginDraw();


            var brush = m_bitmapBrush;

            brush.Alignment = BrushAlignment.DrawingLayerAbsolute;
            brush.Opacity = 0.2f;
            m_presenter.FillRectangle(brush, new RectangleF(0, 0, m_bitmap.Width, m_bitmap.Height));

            brush.Opacity = 1f;

            brush.Alignment = BrushAlignment.GeometryRelative;
            RenderElement(brush, 100, 100, 50, 100);

            brush.Alignment = BrushAlignment.GeometryAbsolute;
            RenderElement(brush, 280, 100, 130, 130);

            brush.Alignment = BrushAlignment.DrawingLayerAbsolute;
            RenderElement(brush, 100, 300, 50, 100);

            brush.Alignment = BrushAlignment.DrawingLayerRelative;
            RenderElement(brush, 280, 300, 50, 100);


            brush.Alignment = BrushAlignment.DrawingLayerAbsolute;
            m_pathGeometry.Transform = new TranslateTransform() {X = m_mousePosition.X, Y = m_mousePosition.Y};
            m_presenter.FillGeometry(brush, m_pathGeometry);

            m_presenter.EndDraw();
        }

        private void RenderElement(Brush brush, float x, float y, float width, float height)
        {
            var ellipse = new Ellipse(new PointF(x + (width/2), y+ (height/2)), width, height);
            m_rotateTransform.CenterX = ellipse.Center.X;
            m_rotateTransform.CenterY = ellipse.Center.Y;
            m_presenter.FillEllipse(brush, ellipse, m_rotateTransform);
            m_presenter.DrawText(m_solidColorBrush, brush.Alignment.ToString(), x - width / 2, y - height / 2);
        }


        private void Initialize()
        {
            SetupGeometry();

            m_solidColorBrush = m_presenter.Factory.CreateSolidColorBrush(new Color4(1, 1, 1, 1));
            m_bitmap = m_presenter.Factory.CreateDrawingLayerFromFile(@".\Assets\Nature Mountains photo.jpg");
            m_bitmapBrush = m_presenter.Factory.CreateDrawingLayerBrush(m_bitmap);

            GradientStop[] stops = new GradientStop[3];

            stops[0].Position = 0;
            stops[0].Color = new Color4(1f, 1, 0, 0);

            stops[1].Position = 0.5f;
            stops[1].Color = new Color4(1f, 0, 1, 0);

            stops[2].Position = 1f;
            stops[2].Color = new Color4(.1f, 0, 0, 1);

            m_gradientBrush = m_presenter.Factory.CreateLinearGradientBrush(stops, ExtendMode.Clamp, new PointF(0, 0), new PointF(SCENE_WIDTH, 0));
            m_gradientBrush.Transform = new RotateTransform();

            m_radialBrush = m_presenter.Factory.CreateRadialGradientBrush(stops, 
                                                                                   ExtendMode.Clamp,
                                                                                   new PointF(500, 500),
                                                                                   new PointF(0, 0),
                                                                                   new SizeF(500, 500));
        }

        private void SetupGeometry()
        {
            XDocument xml = XDocument.Load(@".\Assets\svg.txt");

            var query = from p in xml.Descendants()
                        select p;

            m_pathGeometry = m_presenter.Factory.CreatePathGeometry();
            m_pathGeometry.BeginModify(FillMode.Winding);

            foreach (var xElement in query)
            {
                if(xElement.Name.LocalName == "polygon")
                {
                    var dataAttrib = xElement.Attribute("points").Value;
                    var points = GetLinePoints(dataAttrib);

                    m_pathGeometry.BeginFigure(FigureBegin.Filled, points[0]);

                    foreach (var pointF in points)
                    {
                        m_pathGeometry.AddLine(pointF);
                    }

                    m_pathGeometry.EndFigure(FigureEnd.Closed);
                }
            }

            m_pathGeometry.EndModify();
           
            return;
        }

        private static PointF[] GetLinePoints(string data)
        {
            var points = new List<PointF>();

            data = data.Replace("\r\n", " ");

            string[] dataArray = data.Split(' ');

            foreach (var s in dataArray)
            {
                if(!string.IsNullOrEmpty(s))
                {
                    var dataItems = s.Split(',');

                    points.Add(new PointF(Int32.Parse(dataItems[0]), Int32.Parse(dataItems[1])));
                }
            }

            return points.ToArray();
        }
    }
}
